function fn1(a, b) {
  console.log("this", this);
  console.log(a, b);
  return "this is fn1";
}

// 使用 apply
console.log(fn1.apply({ x: 100 }, [10, 20]));

// 使用call
console.log(fn1.call({ x: 100 }, 10, 20));

// 使用bind
const fn2 = fn1.bind({ x: 100 }, 10, 20);

console.log(fn2());

// 手写bind 函数
Function.prototype.bind1 = function () {
  // 将参数拆解为数组
  const args = Array.prototype.slice.call(arguments);

  // 获取this (数组第一项)

  const t = args.shift();

  // this 指向 fn1

  const self = this;

  return function () {
    return self.apply(t, args);
  };
};

const fn3 = fn1.bind1({ x: 100 }, 10, 20);

console.log(fn3());

//手写 apply 函数
Function.prototype.apply1 = function (obj, arg) {
  obj = obj !== null && typeof obj === "object" ? obj : {};

  obj._apply = this;

  let result = obj._apply(...arg);

  delete obj._apply;

  return result;
};

console.log(fn1.apply1({ x: 100 }, [10, 20]));

// 参数解构赋值，多个参数变一个数组，一个数组变多个参数

// 手写 call 函数
Function.prototype.call1 = function (obj, ...arg) {
  obj = obj !== null && typeof obj === "object" ? obj : {};

  obj._call = this;

  let result = obj._call(...arg);

  delete obj._call;

  return result;
};

console.log(fn1.call1({ x: 100 }, 10, 20));
